package com.blog.shiro;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.AnonymousFilter;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.*;

/**
 * @author gxcc3
 * @create 2021/9/24 21:45
 * shiro配置类
 */
@Configuration
public class ShiroConfig {

    //取redis连接配置
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;

    /**
     * 第三步设置shiroFilterFactoryBean
     * @param
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("webSecurityManager") DefaultWebSecurityManager webSecurityManager){
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        filterFactoryBean.setSecurityManager(webSecurityManager);

        /**
         * 添加shiro内置过滤器
         *
         * anon 无需认证就可以用
         * authc 必须认证了才可以用
         * user 必须有记住我才可以使用
         * perms 拥有某个资源的权限
         * role 拥有某个角色权限才可以访问
         */

        //可以使用链式编程
        Map<String,String> filterMap = new LinkedHashMap<>();
        //后台主页需要权限进行访问
        filterMap.put("/admin/**","perms[admin:admin:admin]");
        filterMap.put("/system/**","perms[all]");
        filterMap.put("/admin/user/user-index","perms[all]");
        filterMap.put("/admin/user/user-index","perms[all]");
        filterMap.put("/index/personCenter","authc");
        filterMap.put("/article/write/**","authc");
        filterMap.put("/comment/article/getComment","anon");
        filterMap.put("/comment/articleDetail/saveComment","authc");
        filterMap.put("/comment/username/changeUserActive","authc");
        filterMap.put("/menu/getSysMenu","anon");
        filterMap.put("/menu/admin/menuInfo","anon");

        LinkedHashMap<String, Filter> map = new LinkedHashMap<>();
        map.put("authc",new MyAuthenticationFilter());
        filterFactoryBean.setFilters(map);

        filterFactoryBean.setFilterChainDefinitionMap(filterMap);
        //没有登录认证跳转至登录页面认证
        filterFactoryBean.setLoginUrl("/login");
        //没有权限提示页面
        filterFactoryBean.setUnauthorizedUrl("/noAuth");

        return filterFactoryBean;
    }




    /**
     * 第二步，设置DefaultWebSecurityManager
     * @param
     * @return
     */
    @Bean(name = "webSecurityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager webSecurityManager = new DefaultWebSecurityManager();

        //关联我们自定义的realm
        webSecurityManager.setRealm(userRealm);

        return webSecurityManager;
    }

    /**
     * 第一步创建realm对象，这个realm类需要自己写
     * @param
     * @return
     */
    @Bean(name = "userRealm")
    public UserRealm userRealm(){
        return new UserRealm();
    }



    /**
     * shiro整合thymeleaf
     * @param
     * @return
     */
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }


    @Bean
    public RedisManager redisManager() {
        // crazycake 实现
        RedisManager redisManager = new RedisManager();
//        RedisClusterManager redisClusterManager = new RedisClusterManager();
        redisManager.setHost(host+":"+port);
//        redisManager.setPort(port);
        redisManager.setTimeout(180000);
        return redisManager;
    }

    @Bean
    public JavaUuidSessionIdGenerator sessionIdGenerator(){
        return new JavaUuidSessionIdGenerator();
    }

    @Bean
    public RedisSessionDAO sessionDAO(){
        RedisSessionDAO sessionDAO = new RedisSessionDAO(); // crazycake 实现
        sessionDAO.setRedisManager(redisManager());
        sessionDAO.setSessionIdGenerator(sessionIdGenerator()); //  Session ID 生成器
        return sessionDAO;
    }
}
